Skip to content

fix(renderer): resolve relative .md links against a leaf page's parent dir#573

Merged
yumike merged 1 commit into
mainfrom
fix-relative-md-links
Jun 23, 2026
Merged

fix(renderer): resolve relative .md links against a leaf page's parent dir#573
yumike merged 1 commit into
mainfrom
fix-relative-md-links

Conversation

@yumike

@yumike yumike commented Jun 23, 2026

Copy link
Copy Markdown
Collaborator

Problem

Relative .md links from a leaf page resolved one directory too deep. For example, [inbox](./inbox.md) in docs/specs/notif.md produced /specs/notif/inbox instead of the sibling /specs/inbox (a 404). The renderer treated every page's clean URL as its containing directory — correct for directory-index pages (index.md, the README homepage), but wrong for leaf name.md pages, whose siblings live in the parent directory. Per CommonMark, ./sibling.md is a sibling of the source file.

Fix

Carry an is_dir flag from the scanner through DocumentPageRenderConfig:

  • true for a directory URL (index.md, README homepage, virtual page)
  • false for a leaf file (name.md)

It's applied as a one-time base-path correction at the existing link seam (beside strip_origin, before transform_link): for a leaf page, the page's own URL slug is dropped before relative links resolve. The generic RenderBackend trait and the resolver are untouched, and README / docs/-prefix homepage links are unchanged.

is_dir is #[serde(default = true)] on the serialized Document (S3 bundle) and Page (structure cache), so data written before the field existed deserializes to the prior behavior — no migration needed.

Behavior

Leaf page specs/notif.md (URL /specs/notif):

Link Resolves to
./inbox.md /specs/inbox
../x.md /x
sub/y.md /specs/sub/y

Index page specs/notif/index.md (URL /specs/notif) is unchanged (./inbox.md/specs/notif/inbox).

Testing

  • Renderer unit/render tests for leaf sibling/parent/subdir/fragment + index regression + root-leaf
  • Scanner classification test (index.md → dir, leaf → file) and README-homepage assertion
  • Document/Page serde-default backward-compat tests
  • End-to-end rw-site test through the real FsStorage scanner
  • Full workspace test suite passes; clippy clean on changed crates
  • Verified live in rw serve against a real docs tree: the two previously-broken links now resolve to their sibling pages (200)

🤖 Generated with Claude Code

…t dir

Relative `.md` links from a leaf page resolved one directory too deep —
`[x](./other.md)` in `docs/specs/notif.md` produced `/specs/notif/other`
instead of the sibling `/specs/other` — because the renderer treated every
page's clean URL as its containing directory. That is correct only for
directory-index pages (`index.md`, the README homepage); a leaf page
(`name.md`) resolves relative links against its parent, per CommonMark.

Carry an `is_dir` flag from the scanner through Document -> Page ->
RenderConfig (true for a directory URL: index.md/README/virtual; false for
a leaf file). Apply it as a one-time base-path correction at the link seam:
for a leaf page, drop the page's own URL slug before resolving relative
links. The RenderBackend trait and the resolver are untouched, and
README/`docs/`-prefix homepage links are unchanged.

`is_dir` is serde default-true on the serialized Document (S3 bundle) and
Page (structure cache) so data written before the field existed
deserializes to the prior behavior.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@yumike yumike merged commit 0c0716a into main Jun 23, 2026
18 checks passed
@yumike yumike deleted the fix-relative-md-links branch June 23, 2026 10:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant